package com.xms.sdk.data;

import com.xms.core.data.Entity;
import com.xms.core.exception.XmsException;
import com.xms.datacore.SqlDescriptor;
import com.xms.datacore.provider.IDataRepositoryBase;
import com.xms.sdk.core.RetrieverParameter;
import com.xms.sdk.extensions.EntityWrapper;
import com.xms.sdk.query.IQueryResolver;
import com.xms.sdk.query.IQueryResolverFactory;
import com.xms.sdk.query.QueryMetadataDescriptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * OrganizationDataProvider
 * </p>
 *
 * @author migo
 * @since 2021/9/6
 */
@Service
public class OrganizationDataProvider implements IOrganizationDataProvider {
    private IDataRepositoryBase _dataRepositoryBase;
    private IQueryResolverFactory _queryResolverFactory;

    @Autowired
    public void OrganizationDataProvider(IDataRepositoryBase dataRepositoryBase,
                                         IQueryResolverFactory queryResolverFactory) {
        _dataRepositoryBase = dataRepositoryBase;
        _queryResolverFactory = queryResolverFactory;
    }

    private String makeInsertSql(Entity entity) {
        StringBuilder sql = new StringBuilder();
        sql.append("INSERT INTO " + entity.Name);
        sql.append(" (" + String.join(",", entity.keySet()) + ")");
        sql.append(" VALUES(");
        long total = entity.keySet().stream().count();
        for (int i = 0; i < total; i++) {
            sql.append("?");
            if (i < total - 1) sql.append(",");
        }
        sql.append(");");
        return sql.toString();
    }

    @Override
    public UUID create(Entity entity) throws SQLException {
        entity = EntityWrapper.unWrapAttributeValue(entity);
        boolean flag = _dataRepositoryBase.execute(new SqlDescriptor(makeInsertSql(entity), entity.values().toArray()));
        if (!flag) {
            return null;
        }
        return entity.getIdValue();
    }

    @Override
    public boolean createMany(List<Entity> entities) throws SQLException {
        if (entities == null || entities.size() == 0) {
            return false;
        }
        StringBuilder sql = new StringBuilder();
        List<Object> values = new ArrayList<>();
        String insertSql = null;
        boolean sqlGenerated = false;
        for (int i = 0; i < entities.size(); i++) {
            Entity entity = EntityWrapper.unWrapAttributeValue(entities.get(i));
            if (!sqlGenerated) insertSql = makeInsertSql(entity);
            values.addAll(entity.values());
            sql.append(insertSql);
        }
        _dataRepositoryBase.execute(new SqlDescriptor(sql.toString(), values));
        return false;
    }

    @Override
    public boolean update(Entity entity) throws SQLException {
        entity = EntityWrapper.unWrapAttributeValue(entity);
        String primaryKey = entity.getIdName();
        UUID id = entity.getIdValue();
        entity.remove(primaryKey);
        StringBuilder sql = new StringBuilder();
        sql.append("UPDATE " + entity.Name);
        sql.append(" SET ");
        List<String> sets = new ArrayList<>();
        List<Object> values = new ArrayList<>();
        for (String k : entity.keySet()) {
            values.add(entity.get(k));
            sets.add(k + "=?");
        }
        values.add(id);
        sql.append(String.join(",\n", sets));
        sql.append(String.format("\nWHERE %s=?", primaryKey));
        return _dataRepositoryBase.execute(new SqlDescriptor(sql.toString(), values));
    }

    @Override
    public boolean update(Entity entity, RetrieverParameter parameters, QueryMetadataDescriptor metadataDescriptor) throws SQLException, XmsException {
        entity = EntityWrapper.unWrapAttributeValue(entity);
        String primaryKey = entity.getIdName();
        entity.remove(primaryKey);
        List<String> sets = new ArrayList<>();
        List<Object> values = new ArrayList<>();
        IQueryResolver queryResolver = _queryResolverFactory.getResolver(parameters.getQuery());
        SqlDescriptor queryString = queryResolver.toSqlString(parameters, metadataDescriptor);
        StringBuilder sql = new StringBuilder();
        sql.append("UPDATE " + entity.Name);
        sql.append(" SET ");
        for (String k : entity.keySet()) {
            values.add(entity.get(k));
            sets.add(k + "=?");
        }
        for (Object arg : queryString.getFinalArgs()){
            values.add(arg);
        }
        //values.addAll(Arrays.asList(queryString.getFinalArgs()));
        sql.append(String.join(",\n", sets));
        sql.append(String.format("\n WHERE %s IN(%s)", primaryKey, queryString.getFinalSql()));
        return _dataRepositoryBase.execute(new SqlDescriptor(sql.toString(), values));
    }

    @Override
    public boolean delete(String name, UUID id) throws SQLException {
        return this.delete(name, id, "");
    }

    @Override
    public boolean delete(String name, UUID id, String primarykey) throws SQLException {
        StringBuilder sql = new StringBuilder();
        sql.append("DELETE FROM " + name);
        sql.append(String.format("\n WHERE %s=?", primarykey.isEmpty() ? name + "id" : primarykey));
        return _dataRepositoryBase.execute(new SqlDescriptor(sql.toString(), id));
    }
}
